//--------------------------------------------------------------------------------------------------
//                                                   ___  __  __  __  __  __  __  __    __  __  ___ 
// Copyright 2010, Koert van der Veer.              / __)(  )(  )(  \/  )(  )(  )(  )  (  )(  )/ __)
// Licensed under the Apache License,              ( (__  )(__)(  )    (  )(__)(  )(__  )(__)( \__ \
// version 2.0; ("the License")                     \___)(______)(_/\/\_)(______)(____)(______)(___/

// You may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
//     http://www.apache.org/licenses/LICENSE-2.0 
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS,  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License. 
//--------------------------------------------------------------------------------------------------
// This file is part of cumulus,  an memory manager implementation in C++.  Details are discussed in
// my blog,  which can be found at http://ondergetekende.nl.  Comments,  suggestions and bug reports
// are welcome. They can be added as comments at the blog. Be advised that in its current form, this
// code is most likely not production ready; it simply hasn't been tested sufficiently. 
//--------------------------------------------------------------------------------------------------
// Miscelanious utilities
//--------------------------------------------------------------------------------------------------

#pragma once

#include <assert.h>
#include <memory.h>

// Make sure we have a NULL macro
#ifndef NULL
	#define NULL 0
#endif

namespace Cumulus
{
	class NonCopyable
	{
	private:
		NonCopyable( const NonCopyable& );
	protected:
		NonCopyable() {};
	};

	class NonAssignable : public NonCopyable
	{
	private:
		void operator = ( const class NonAssignable& );
	protected:
		NonAssignable() {};
	};

	/// Finds the alignment of a specific type
	/// @param	T		Type to find the alignment of
	/// Usage:
	///		size_t align = AlignmentOf<int>::Result;
	template< typename T >
	class AlignmentOf 
	{
	private:
		struct s
		{
			char* pad;
			T V;
		};
	public:
		static const size_t Result = (size_t)&((s*)0)->V;
	};

	/// Finds a pointer to a header prefixed to the given pointer
	/// @param	T		Type of the prefixed header
	/// @param	Ptr		Pointer to first byte after the header to find
	/// @return Pointer to the prefixed header
	template< typename T >
	inline T* GetHeader( void* Ptr )
	{
		return reinterpret_cast<T*>(Ptr) - 1;
	}

	/// @param	T		Type of the prefixed header
	/// @param	Header	Pointer to first byte after the header to find
	/// @return a pointer to the first byte after @Header
	template< typename T >
	inline void* GetPayload( T* Header )
	{
		return reinterpret_cast<void*>( Header + 1 );
	}

	// Declare a template, but forward declare the false specialization..
	// This will generate an error whenever the false specialization is needed, e.g.
	// when the assertion failed.
	// Note that the condition is a bit hard to formulate, because compilers tend to
	// confuse the greater or less operators with the template braces.
	// Usage: 
	//     static CompileTimeAssert< sizeof(void*) == 4 > Only32BitSupport
	template< bool AssertionToCheck > struct CompileTimeAssert { };
	template<> struct CompileTimeAssert< false >; // Forward declarations

	// Selects a type based on the provided condition.
	// Note that the condition is a bit hard to formulate, because compilers tend to
	// confuse the greater or less operators with the template braces.
	// Usage:
	//		SelectType< sizeof(int*) == 4, LargePointer, SmallPointer >::Result
	template< bool Condition, typename IfTrue, typename IfFalse > 
	struct SelectType
	{
	private:
		// default implementation yields IfTrue;
		template< bool Condition > struct Selector {typedef IfTrue ResultType;};     
		// false implementation yields IfFalse;
		template<> struct Selector< false > {typedef IfFalse ResultType;};     

	public:
		// Typedef the template into Result.
		typedef typename Selector< Condition >::ResultType Result;
	};

	// Returns the Log2 of v, rounded down. Implementation adapted from 
	// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
	inline unsigned int IntLog2( unsigned int v )
	{
		unsigned int r = 0; // result of log2(v) will go here

		if( v & 0xFFFF0000 ) { r |= 16;v >>= 16; } 
		if( v & 0x0000FF00 ) { r |= 8; v >>= 8; } 
		if( v & 0x000000F0 ) { r |= 4; v >>= 4; } 
		if( v & 0x0000000C ) { r |= 2; v >>= 2; } 
		if( v & 0x00000002 ) { r |= 1; } 

		return r;
	}

	// Returns the Log2 of v, rounded down. Implementation adapted from 
	// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
	inline unsigned int IntLog2( unsigned long long v )
	{
		unsigned int r = 0; // result of log2(v) will go here

		if( v & 0xFFFFFFFF00000000ULL ) { r |= 32;v >>= 32; } 
		if( v & 0x00000000FFFF0000ULL ) { r |= 16;v >>= 16; } 
		if( v & 0x000000000000FF00ULL ) { r |= 8; v >>= 8; } 
		if( v & 0x00000000000000F0ULL ) { r |= 4; v >>= 4; } 
		if( v & 0x000000000000000CULL ) { r |= 2; v >>= 2; } 
		if( v & 0x0000000000000002ULL ) { r |= 1; } 

		return r;
	}

}